package com.ref.demo10;


import java.lang.reflect.Field;
import java.sql.*;
import java.time.*;
import java.util.Date;
import java.util.Map;

/**
 * @ClassName DbUtil
 * @Description 实现从数据库中查询数据，并自动封装到实体类中，如：
 *     public class DbUtil{
 *         // 学过泛型的可以把 Object 改为泛型
 *         public static Object select4Bean(Class<?> beanClass,Map<String,Object> cond){
 *             // 功能实现...
 *         }
 *     }
 *     要求如下：
 *         1、根据参数 beanClass 自动生成查询所有数据的 SQL 语句（上题已实现），
 *         2、cond 为查询条件，需要拼接到查询所有数据的后面，如：
 *             Map<String,Object> cond = new HashMap<>() ;
 *             cond.put("id","1001") ;
 *             cond.put("name","张三") ;
 *             则拼接的 SQL 语句为：select id,name from user where id=? and name=? ;
 *         3、把查询的数据封装到对应的实体对象返回
 * @Author Kx
 * @Date 2025/3/19 10:17
 * @Version 1.0
 */
public class DbUtil {
    /**
     * @description: 执行查询语句获取数据
     * @author: Kx
     * @date: 2025/3/19 15:49
     * @param: [beanClass, cond:查询条件]
     * @return: T
     **/
    public static <T>T select4Bean(Class<T> beanClass, Map<String,Object> cond){
        // 获取查询条件
        String sql = generateSelectSql(beanClass, cond);

        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;

        try {
            // 获取连接对象
            connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/student","root","password");

            // 获取预编译对象
            preparedStatement = connection.prepareStatement(sql);

            int index = 1;

                // 把条件值设置到预编译对象中(即设置到?中)
                // 获取key和value值
                Map.Entry<String,Object> entry = cond.entrySet().iterator().next();

                for (Map.Entry<String,Object> entrys : cond.entrySet()){
                    // 获取字段名
                    String key = entrys.getKey();

                    // 获取字段值
                    Object value = entrys.getValue();

                    // 把字段值设置到预编译对象中
                    preparedStatement.setObject(index++,value);
                }


            // 执行查询并存储到结果集中
            resultSet = preparedStatement.executeQuery();

            return DbUtil.mapper(beanClass,resultSet);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                // 关闭连接
                if (resultSet != null){
                    resultSet.close();
                }
                if (preparedStatement != null) {
                    preparedStatement.close();
                }
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return null;
    }


    /**
     * @description: 根据参数 beanClass 自动生成根据条件查询
     * @author: Kx
     * @date: 2025/3/19 15:28
     * @param: [beanClass, cond]
     * @return: java.lang.String
     **/
    private static String generateSelectSql(Class<?> beanClass, Map<String,Object> cond){
        // 获取所有的字段
        Field[] declaredFields = beanClass.getDeclaredFields();

        // 拼接 SQL 语句
        StringBuilder sql = new StringBuilder("select ");
        for (Field field : declaredFields){
            // 判断字段名中是否有大写字母
            if (field.getName().matches(".*[A-Z].*")) {
                sql.append(field.getName()).append(" as ");
            }
            // 把所有字段名全部转换成小写
            sql.append(field.getName().toLowerCase()).append(",");
        }
        // 去除字段名最后一个参数的逗号
        sql.deleteCharAt(sql.length() - 1);

        sql.append(" from ");

        sql.append(beanClass.getSimpleName().toLowerCase());

        sql.append(" where ");

        // 循环把判断条件拼接到sql语句中
        for (Map.Entry<String,Object> entry : cond.entrySet()){
            sql.append(entry.getKey()).append("=?").append(" and ");
        }

        // 去除最后一个 and
        sql.delete(sql.length() - 4,sql.length());

        return sql.toString();
    }


    /**
     * @description: 把查询结果集封装到实体类中
     * @author: Kx
     * @date:  16:03
     * @param: [beanClass]
     * @return: void
     **/
    private static <T>T mapper(Class<T> beanClass, ResultSet resultSet){
        try {
            // 判断结果集是否为空
            if (!resultSet.next()){
                return null;
            }

            // 获取实体类对象
            T t = beanClass.getDeclaredConstructor().newInstance();

            // 循环遍历所有字段
            for (Field field : beanClass.getDeclaredFields()) {
                // 字段名
                String name = field.getName();

                // 开启访问权限
                field.setAccessible(true);

                // 获取字段值
                Object object = resultSet.getObject(name);

                // 判断字段值是否为空
                if (object == null){
                    field.set(t, getDefaultValue(field.getType()));
                } else {
                    // 如果字段类型是 LocalDateTime，则进行类型转换
                    object = convertType(field.getType(), object);
                    // 把字段值设置到实体类中
                    field.set(t, object);
                }
            }
            return t;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /***
     * @author: kx
     * @date: 2025/3/22 12:03
     * @param beanClass
     * @param resultSet
     * @return java.lang.Object
     * @description:
    */
//    private static Object getBean(Class<?> beanClass,ResultSet resultSet){
//
//    }

    /**
     * @description: 判断字段类型，并返回默认值
     * @author: Kx
     * @date: 2025/3/20 19:35
     * @param: [type]
     * @return: java.lang.Object
     **/
    private static Object getDefaultValue(Class<?> type) {
        if(type == int.class || type == Integer.class){
            return 0;
        } else if (type == short.class || type == Short.class) {
            return 0;
        } else if (type == byte.class || type == Byte.class) {
            return 0;
        } else if (type == long.class || type == Long.class) {
            return 0L;
        } else if (type == float.class || type == Float.class) {
            return 0.0f;
        } else if (type == double.class || type == Double.class) {
            return 0.0;
        } else if (type == boolean.class || type == Boolean.class) {
            return false;
        } else if (type == char.class || type == Character.class) {
            return '\u0000';
        } else {
            return null;
        }
    }

    /**
     * @description: 时间类型转换
     * @author: Kx
     * @date: 2025/3/21 9:11
     * @param: [type, value]
     * @return: java.lang.Object
     **/
    public static Object convertType(Class<?> type,Object value) {
        if (value == null) {
            return getDefaultValue(type);  // 如果值为null，直接返回null
        }

        // 判断并转换 Date 类型
        if (value instanceof Date) {
            return convertFromDate(type, (Date) value);
        }

        // 判断并转换 LocalDateTime 类型
        if (value instanceof LocalDateTime) {
            return convertFromLocalDateTime(type, (LocalDateTime) value);
        }

        return value;  // 如果没有匹配类型，直接返回原始值
    }

    /**
     * @description: 将 Date 类型转换为 LocalDateTime、LocalDate 或 LocalTime
     * @author: Kx
     * @date: 2025/3/21 9:11
     * @param: [type, value]
     * @return: java.lang.Object
     **/
    private static Object convertFromDate(Class<?> type, Date value) {
        Instant instant = value.toInstant(); // 获取 Date 的 Instant
        ZoneId zoneId = ZoneId.systemDefault(); // 获取当前默认时区

        // 判断目标类型并转换
        if (type == LocalDateTime.class) {
            // 转换为 LocalDateTime
            return instant.atZone(zoneId).toLocalDateTime();
        }
        if (type == LocalDate.class) {
            // 转换为 LocalDate
            return instant.atZone(zoneId).toLocalDate();
        }
        if (type == LocalTime.class) {
            // 转换为 LocalTime
            return instant.atZone(zoneId).toLocalTime();
        }
        if (type == Date.class) {
            return value;  // 如果目标类型是 Date，直接返回
        }
        // 如果目标类型不匹配，抛出异常
        throw new IllegalArgumentException("Unsupported conversion from Date to " + type);
    }

    /**
     * @description: 将 LocalDateTime 类型转换为 Date、LocalDate 或 LocalTime
     * @author: Kx
     * @date: 2025/3/21 9:12
     * @param: [type, value]
     * @return: java.lang.Object
     **/
    private static Object convertFromLocalDateTime(Class<?> type, LocalDateTime value) {
        // 获取当前时区
        ZoneId zoneId = ZoneId.systemDefault();
        // 将 LocalDateTime 转换为 Instant
        Instant instant = value.atZone(zoneId).toInstant();

        // 判断目标类型并转换
        if (type == Date.class) {
            return Date.from(instant);
        }
        if (type == LocalDateTime.class) {
            return value;  // 如果目标类型是 LocalDateTime，直接返回
        }
        if (type == LocalDate.class) {
            return value.toLocalDate();  // LocalDateTime 到 LocalDate
        }
        if (type == LocalTime.class) {
            return value.toLocalTime();  // LocalDateTime 到 LocalTime
        }

        throw new IllegalArgumentException("Unsupported conversion from LocalDateTime to " + type);
    }
}